package com.iot08.api.config.redis;

import com.iot08.common.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.exceptions.JedisConnectionException;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 视频模块的的Redis 缓存
 * @version 1.0
 * @Description:
 * @author: Weichao
 * @time: 2020/9/7 11:27
 */
@Slf4j
@Component
public class RedisVideoService {

    @Value("${redis.pool.host-video}")
    private String server;
    @Value("${redis.pool.port-video}")
    private Integer port;
    @Value("${redis.pool.database-video}")
    private Integer database;
    @Value("${redis.pool.password-video}")
    private String password;
    @Value("${redis.pool.maxTotal-video}")
    private Integer poolMaxTotal;
    @Value("${redis.pool.maxIdle-video}")
    private Integer poolMaxIdle;
    @Value("${redis.pool.minIdle-video}")
    private Integer poolMinIdle;
    @Value("${redis.pool.maxWaitMillis-video}")
    private Long poolMaxWaitMillis;
    @Value("${redis.pool.testOnBorrow-video}")
    private Boolean poolTestOnBorrow;
    @Value("${redis.pool.testOnReturn-video}")
    private Boolean poolTestOnReturn;

    private static JedisPool jedisPool;

    @PostConstruct
    private void init() {
        log.info("初始化 redis 单实例配置数据: server={} port={} database={}", server, port, database);
        JedisPoolConfig config = new JedisPoolConfig();
        //最大连接数, 默认8个
        config.setMaxTotal(poolMaxTotal);
        // 最大空闲连接数, 默认8个
        config.setMaxIdle(poolMaxIdle);
        // 最小空闲连接数, 默认8个
        config.setMinIdle(poolMinIdle);
        // 当池内没有对象返回时，最大的等待时间
        config.setMaxWaitMillis(poolMaxWaitMillis);
        // 当调用borrow Object方\法时，是否进行有效性检查
        config.setTestOnBorrow(poolTestOnBorrow);
        // 当调用return Object方法时，是否进行有效性检查
        config.setTestOnReturn(poolTestOnReturn);
        //配置 , host , port , 连接超时时间 ,密码 , DB名字

        // ========== 新增这部分配置 ==========
        // 空闲连接检测 - 这是解决问题的关键
        config.setTestWhileIdle(true);                      // 开启空闲检测
        config.setTimeBetweenEvictionRunsMillis(30000);     // 每30秒运行一次检测
        config.setMinEvictableIdleTimeMillis(60000);        // 连接空闲60秒后回收
        config.setNumTestsPerEvictionRun(3);                // 每次检测3个连接
        // ====================================


        if (StringUtil.isBlank(password)) {
            password = null;
        }
        jedisPool = new JedisPool(config, server, port, 10000, password, database);
//        log.info("jedisPool={} ", jedisPool);
    }


//    /**
//     * @time: 2020/9/25 14:13
//     * @author: Weichao
//     * @version 1.0
//     */
//    private Jedis getRedisClient() {
//        try {
//            return jedisPool.getResource();
//        } catch (Exception e) {
//            log.error("getRedisClient error", e);
//        }
//        return null;
//    }

    private Jedis getRedisClient() {
        // 重试3次
        for (int i = 0; i < 3; i++) {
            log.info("开始尝试获取Redis连接");
            try {
                Jedis jedis = jedisPool.getResource();
                // 验证连接是否正常
                jedis.ping();
                return jedis;
            } catch (Exception e) {
                log.warn("获取Redis连接失败，第{}次尝试", i + 1, e);
                if (i < 2) {  // 不是最后一次尝试
                    try {
                        Thread.sleep(100 * (i + 1));  // 递增等待时间
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        }
        log.error("3次尝试后仍无法获取Redis连接");
        return null;
    }
    /**
     * @param key
     * @param value
     * @time: 2020/11/2 16:30
     * @author: Weichao
     * @version 1.0
     */
    public String set(String key, String value) {
        Jedis jedis = getRedisClient();
        if (jedis != null) {
            try {
                return jedis.set(key, value);
            } finally {
                jedis.close();
            }
        }
        return null;
    }

    /**
     * @param key
     * @param second
     * @param value
     * @time: 2020/11/4 11:29
     * @author: Weichao
     * @version 1.0
     */
    public String setex(String key, int second, String value) {
        Jedis jedis = getRedisClient();
        if (jedis != null) {
            try {
                return jedis.setex(key, second, value);
            } finally {
                jedis.close();
            }
        }
        return null;
    }

    /**
     * @param key
     * @time: 2020/11/2 16:31
     * @author: Weichao
     * @version 1.0
     */
//    public String get(String key) {
//        Jedis jedis = getRedisClient();
//        if (jedis != null) {
//            try {
//                return jedis.get(key);
//            } finally {
//                jedis.close();
//            }
//        }
//        return null;
//    }

    public String get(String key) {
        Jedis jedis = getRedisClient();
        if (jedis != null) {
            try {
                return jedis.get(key);
            } catch (JedisConnectionException e) {
                log.warn("连接异常，重试get操作: key={}", key, e);
                // 关闭坏连接
                try { jedis.close(); } catch (Exception ex) {}

                // 获取新连接重试一次
                jedis = getRedisClient();
                if (jedis != null) {
                    try {
                        return jedis.get(key);
                    } finally {
                        jedis.close();
                    }
                }
            } catch (Exception e) {
                log.error("Redis get操作失败: key={}", key, e);
            } finally {
                jedis.close();
            }
        }
        return null;
    }

    /**
     * @param key
     * @param field
     * @time: 2020/10/17 10:17
     * @author: Weichao
     * @version 1.0
     */
    public String hget(String key, String field) {
        Jedis jedis = getRedisClient();
        if (jedis != null) {
            try {
                return jedis.hget(key, field);
            } finally {
                jedis.close();
            }
        }
        return null;
    }


    /**
     * 获取多个 hex Map 的值
     * @param key
     * @param fields
     * @time: 2021/08/25 15:17
     * @author: Weichao
     * @version 1.0
     */
    public List<String> hmget(String key, String... fields) {
        Jedis jedis = getRedisClient();
        if (jedis != null) {
            try {
                return jedis.hmget(key, fields);
            } finally {
                jedis.close();
            }
        }
        return null;
    }

    /**
     * @param key
     * @param field
     * @param value
     * @time: 2020/9/25 14:19
     * @author: Weichao
     * @version 1.0
     */
    public Long hset(String key, String field, String value) {
        Jedis jedis = getRedisClient();
        if (jedis != null) {
            try {
                return jedis.hset(key, field, value);
            } finally {
                jedis.close();
            }
        }
        return null;
    }

    /**
     * @param key
     * @param field
     * @time: 2020/9/25 14:20
     * @author: Weichao
     * @version 1.0
     */
    public Long hdel(String key, String field) {
        Jedis jedis = getRedisClient();
        if (jedis != null) {
            try {
                return jedis.hdel(key, field);
            } finally {
                jedis.close();
            }
        }
        return null;
    }

    /**
     * @param key
     * @time: 2020/10/20 11:17
     * @author: Weichao
     * @version 1.0
     */
    public Long del(String key) {
        Jedis jedis = getRedisClient();
        if (jedis != null) {
            try {
                return jedis.del(key);
            } finally {
                jedis.close();
            }
        }
        return null;
    }

    /**
     * @param keys
     * @time: 2020/10/20 11:17
     * @author: WeiChao
     * @version 1.0
     */
    public Long mdel(String... keys) {
        Jedis jedis = getRedisClient();
        if (jedis != null) {
            try {
                return jedis.del(keys);
            } finally {
                jedis.close();
            }
        }
        return null;
    }


    /**
     * @param key
     * @time: 2021/1/15 11:09
     * @author: Weichao
     * @version 1.0
     */
    public Map<String, String> hgetAll(String key) {
        Jedis jedis = getRedisClient();
        if (jedis != null) {
            try {
                return jedis.hgetAll(key);
            } finally {
                jedis.close();
            }
        }
        return null;
    }

    /**
     * @param key
     * @param value
     * @time: 2021/1/15 11:23
     * @author: Weichao
     * @version 1.0
     */
    public void hmset(String key, Map<String, String> value) {
        Jedis jedis = getRedisClient();
        if (jedis != null) {
            try {
                jedis.hmset(key, value);
            } finally {
                jedis.close();
            }
        }
    }

    /**
     * @param key
     * @time: 2021/2/26 9:10
     * @author: Weichao
     * @version 1.0
     */
    public Set<String> keys(String key) {
        Jedis jedis = getRedisClient();
        if (jedis != null) {
            try {
                return jedis.keys(key);
            } finally {
                jedis.close();
            }
        }
        return null;
    }

}
